package com.heo.coder;

import java.util.List;
import org.apache.log4j.Logger;

import com.heo.coder.packet.SocketPacket;
import com.heo.coder.packet.base.BasePacket;
import com.heo.util.ByteHelper;
import com.heo.util.Utils;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

public class BikeDeviceDecoder extends ByteToMessageDecoder {
	
	private static Logger log = Logger.getLogger(BikeDeviceDecoder.class);
	
	@Override
	protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
		if(in.readableBytes() < BasePacket.START_MARKER_LENGTH) {
			return ;
		}
		
		in.markReaderIndex();
		
		byte[] startByte = new byte[BasePacket.START_MARKER_LENGTH];
		in.readBytes(startByte);

		String startCode = ByteHelper.byteToHexStringNoSpace(startByte);
		
        if(!BasePacket.START_MARKER_LENGTH_CODE.equals(startCode)) {
        	ctx.close();
        	return;
        }
        
        if(in.readableBytes() < BasePacket.HEAD_LENGTH) {
        	in.resetReaderIndex();
            return;
        }
        
        
        String headCode = hexReplace(in, BasePacket.HEAD_LENGTH, BasePacket.HEAD_LENGTH, "", false);
        if(!Utils.checkNull(headCode)) {
    		in.resetReaderIndex();
            return;
    	}
        
        String commandId = headCode.substring(0, 4);
        String head =  headCode.substring(4, 8);
        String msgBin = ByteHelper.hexString2binaryString(head);
        String reserve = msgBin.substring(0, 2);
    	String subcontract = msgBin.substring(2, 3);
    	String rsa = msgBin.substring(3, 6);
    	String bodyLengthStr = msgBin.substring(6);
    	int bodyLength = ByteHelper.binary2Int(bodyLengthStr); // 消息体长度 0000 0000 0000 0110 6
    	String imei = headCode.substring(8, 20);
    	String sequenceId = headCode.substring(20);
    	
    	if(in.readableBytes() < bodyLength + BasePacket.CHECK_LENGTH + BasePacket.END_MARKER_LENGTH) {
        	in.resetReaderIndex();
            return;
        }
    	
    	String msgContent = "";
    	
    	if(bodyLength > 0) {
    		msgContent = hexReplace(in, bodyLength, bodyLength, "", false);
        	if(!Utils.checkNull(msgContent)) {
        		in.resetReaderIndex();
                return;
        	}
    	}
    	
    	if(in.readableBytes() < BasePacket.CHECK_LENGTH) {
        	in.resetReaderIndex();
            return;
        }
        byte[] bytes = new byte[BasePacket.CHECK_LENGTH]; // 传输正常
        in.readBytes(bytes);
    	String checkCode = ByteHelper.byteToHexStringNoSpace(bytes);
    	if(BasePacket.REPLACE_7D.equals(checkCode)) {
    		if(in.readableBytes() < BasePacket.CHECK_LENGTH) {
            	in.resetReaderIndex();
                return;
            }
    		bytes = new byte[1]; // 传输正常
            in.readBytes(bytes);
        	checkCode = checkCode + ByteHelper.byteToHexStringNoSpace(bytes);
        	checkCode = ByteHelper.stringReplace(checkCode, BasePacket.REPLACE_7D01, BasePacket.REPLACE_7D);
        	checkCode = ByteHelper.stringReplace(checkCode, BasePacket.REPLACE_7D02, BasePacket.REPLACE_7E);
    	}
    	
    	
    	String hexCheck = commandId + head + imei + sequenceId + msgContent;
    	byte[] hexCheckBytes = ByteHelper.hexStringToBytes(hexCheck);
		byte xorByte = ByteHelper.getXor(hexCheckBytes);
		String checkCodeStr = ByteHelper.byteToHexString(new byte[] {xorByte});
		if(checkCodeStr.equals(checkCode)) {
			log.info("BikeDeviceDecoder 效验码 = " + checkCode + " 平台计算结果" + checkCodeStr + "校验结果 = " + true);
		}else {
			log.info("BikeDeviceDecoder 效验码 = " + checkCode + " 平台计算结果" + checkCodeStr + "校验结果 = " + false + "断开链接");
			ctx.close();
        	return;
		}
    	
    	if(in.readableBytes() < BasePacket.END_MARKER_LENGTH) {
        	in.resetReaderIndex();
            return;
        }
    	bytes = new byte[BasePacket.END_MARKER_LENGTH]; // 传输正常
        in.readBytes(bytes);
    	String endCode = ByteHelper.byteToHexStringNoSpace(bytes);
    	if(!BasePacket.END_MARKER_LENGTH_CODE.equals(endCode)) {
    		ctx.close();
        	return;
    	}
    	
    	SocketPacket socketPacket = new SocketPacket(commandId, reserve, subcontract, rsa, bodyLength, imei,
    		 sequenceId, msgContent, checkCode);
    	socketPacket.setHead(head);
        out.add(socketPacket);
	}
	
	private String hexReplace(ByteBuf in, int size, int length, String returnCode, boolean bool) {
		if(in.readableBytes() < size) {
            return "";
        }
		byte[] bytes = new byte[size]; // 传输正常
        in.readBytes(bytes);
        String headCode = ByteHelper.byteToHexStringNoSpace(bytes);
        headCode = returnCode + headCode;
        headCode = ByteHelper.stringReplace(headCode, BasePacket.REPLACE_7D01, BasePacket.REPLACE_7D);
        headCode = ByteHelper.stringReplace(headCode, BasePacket.REPLACE_7D02, BasePacket.REPLACE_7E);
        int codeLength = headCode.length() / 2;
        if(codeLength == length && (!headCode.endsWith(BasePacket.REPLACE_7D) || bool)) {
        	return headCode;
        }else {
        	size = 0;
        	if(codeLength != length) {
        		size = length - codeLength;
        	}
        	if(headCode.endsWith(BasePacket.REPLACE_7D)) {
        		size = size + 1;
        	}
        	return hexReplace(in, size, length, headCode, true);
        }
	}

}
